package com.caishi.lkx.user.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.caishi.lkx.user.dto.LoginDto;
import com.caishi.lkx.user.ienum.type.AgentRechargeType;
import com.caishi.lkx.user.ienum.type.UserAccountType;
import com.caishi.lkx.user.ienum.type.UserType;
import com.caishi.lkx.user.mapper.AgentUserMapper;
import com.caishi.lkx.user.model.*;
import com.caishi.lkx.user.service.*;
import com.zzw.common.Wrappers;
import com.zzw.common.entity.IBaseMapper;
import com.zzw.common.entity.impl.BaseIntEntity;
import com.zzw.common.exception.BizException;
import com.zzw.common.exception.BizRuntimeException;
import com.zzw.common.lock.RedissonLock;
import com.zzw.common.threadpool.SysThreadPool;

import com.caishi.lkx.user.UserResultCode;

import com.caishi.lkx.user.login.LoginServiceComposite;

import lombok.extern.slf4j.Slf4j;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @Author: huangpeng
 * @Date: 2021/9/26 15:02
 * @Description:
 */
@Service("agentUserService")
@Slf4j
//@DubboService(interfaceClass = IAgentUserBaseService.class)
public class AgentUserServiceImpl implements IAgentUserService {

    @Resource
    private AgentUserMapper agentUserMapper;

    @Resource
    private IUserService<UserModel> userService;

    @Resource
    private LoginServiceComposite loginServiceComposite;

    @Resource
    private IAgentLevelService agentLevelService;
    @Resource
    private IActionRoleService actionRoleService;

    @Resource
    private IPositionService positionService;
    @Resource
    private IAgentRechargeService agentRechargeService;
    @Resource
    private IDistributionUserService IDistributionUserService;

    @Override
    public IBaseMapper<AgentUserModel, String> getMapper() {
        return agentUserMapper;
    }

    @Override
    public IUserService<UserModel> baseService() {
        return userService;
    }

    @Override
    public AgentUserModel register(LoginDto loginDto, HttpServletRequest request, HttpServletResponse response) throws BizException {
        throw new BizException();
    }

    @Override
    public AgentUserModel register(AgentUserModel userModel) {
        if (userModel.getUserType() == 0) {
            userModel.addUserType(UserType.agent);
        }
        UserModel baseModel = userService.register(userModel.toUserModel());
        userModel.userInfoCopy(baseModel);
        return registerCheck(baseModel, userModel);
    }

    private AgentUserModel registerCheck(UserModel baseUser, AgentUserModel model) {
        if (agentUserMapper.contains(baseUser.getId())) {
            this.simpleUpdate(model.clearUserModelMessage());
            return model;
        }
        model = model.clearUserModelMessage();
        model.setId(baseUser.getId());
        return this.insert(model).userInfoCopy(baseUser);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public AgentUserModel addUser(AgentUserModel model, List<String> roleIds, List<String> positionCodes, String username, String password, UserAccountType loginType) throws BizException {
        Assert.notEmpty(model.getMobile(), "手机号不能为空");
        Assert.isTrue(model.getUserType() != null && model.getUserType() != 0);
        IUserModel userModel = loginServiceComposite.register(
                LoginInfoModel.builder()
                        .account(username)
                        .loginType(loginType)
                        .certificate(password)
                        .build(),
                model
        );
        if (CollUtil.isNotEmpty(roleIds)) {
            actionRoleService.userSettingRolesByIds(model.getId(), roleIds);
        }
        //tttt
        if (CollUtil.isNotEmpty(positionCodes)) {
            List<Long> collect = positionService.selectList(Wrappers.<PositionModel>lambdaQuery().in(PositionModel::getCode, positionCodes))
                    .stream().map(BaseIntEntity::getId).collect(Collectors.toList());
            positionService.userSettingPositionByIds(userModel.getId(), collect);
        }
        return model;
    }

    @Override
    public IPage<AgentUserModel> search(Map<String, Object> param, Page<AgentUserModel> page, Boolean total) {
        Future<Long> future = CompletableFuture.supplyAsync(() -> null);
        if (total) {
            future = SysThreadPool.submit(() -> agentUserMapper.searchUserCount(param));
        }
        List<AgentUserModel> adminUserModels = agentUserMapper.searchUser(page.offset(), page.getSize(), param,
                page.getOrders().stream().filter(OrderItem::isAsc).map(OrderItem::getColumn).collect(Collectors.toList()),
                page.getOrders().stream().filter(o -> !o.isAsc()).map(OrderItem::getColumn).collect(Collectors.toList())
        );
        try {
            Long count = future.get();
            return page.setRecords(adminUserModels).setTotal(count == null ? page.getRecords().size() : count);
        } catch (InterruptedException | ExecutionException e) {
            throw new BizRuntimeException(e);
        }
    }

    @Override
    public List<AgentUserModel> searchList(Map<String, Object> param, long size) {
        return agentUserMapper.searchUser(0L, size, param, null, null);
    }

//    @Override
//    public AgentUserModel update(AgentUserModel entity) {
//        UserModel baseUser = userService.update(entity.toUserModel());
//        agentUserMapper.updateById(entity.clearUserModelMessage());
//        return entity.userInfoCopy(baseUser);
//    }
//
//    @Override
//    public AgentUserModel simpleUpdate(AgentUserModel entity) {
//        UserModel baseUser = userService.simpleUpdate(entity.toUserModel());
//        agentUserMapper.updateById(entity.clearUserModelMessage());
//        return entity.userInfoCopy(baseUser);
//    }


    @Override
//    @Transactional(rollbackFor = Exception.class)
    public Boolean recharge(String id, Long money, AgentRechargeType type) {
        try {
            RedissonLock.lock(id + ":agent:money:lock", k -> {
                AgentUserModel agentUser = this.getById(id);
                if (null == agentUser) {
                    throw new BizRuntimeException(UserResultCode.agentNotExist);
                }
                AgentUserModel newAgent = AgentUserModel.builder().build();
                newAgent.setId(agentUser.getId());
                //充值

                long add = agentUser.getBanance() + money;
                if (add < 0) {
                    throw new BizRuntimeException(UserResultCode.agentBalanceOff);
                }
                newAgent.setBanance(add);
                if (money > 0) {
                    newAgent.setAccumulativeRecharge(agentUser.getAccumulativeRecharge() + money);
                }
                agentUserMapper.updateById(newAgent);
            });
        } catch (Exception e) {
            log.error(e.getMessage());
            log.error("代理商充值失败:{},{}", id, money);
            throw new BizRuntimeException(UserResultCode.agentRechargeException);
        }
        return true;
    }

    @Override
    public Boolean refuse(String id, Long money, String remark) {
        try {
            RedissonLock.lock(id + ":agent:money:lock", k -> {
                AgentUserModel agentUser = this.getById(id);
                if (null == agentUser) {
                    throw new BizRuntimeException(UserResultCode.agentNotExist);
                }
                AgentRechargeModel entity = AgentRechargeModel.builder().amount(money).userId(id).remark(remark).type(AgentRechargeType.orderRefund).build();
                agentRechargeService.insert(entity);
            });
        } catch (Exception e) {
            log.error("代理商退款失败:{},{}", id, money);
            throw new BizRuntimeException(UserResultCode.agentRefundException);
        }
        return true;
    }

    @Override
//    @Transactional(rollbackFor = Exception.class)
    public Boolean cosumer(String id, Long money, String remark) {
        try {
            RedissonLock.lock(id + ":agent:money:lock", k -> {
                AgentUserModel agentUser = this.getById(id);
                if (null == agentUser) {
                    throw new BizRuntimeException(UserResultCode.agentNotExist);
                }
                if (agentUser.getBanance() < money) {
                    throw new BizRuntimeException(UserResultCode.agentBalanceOff);
                }
                AgentUserModel newAgent = AgentUserModel.builder().build();
                newAgent.setId(agentUser.getId());

                newAgent.setBanance(agentUser.getBanance() - money);
                newAgent.setCumulativeConsumption(agentUser.getCumulativeConsumption() + money);
                AgentRechargeModel entity = AgentRechargeModel.builder().amount(money * -1).userId(id).remark(remark).type(AgentRechargeType.orderConsum).build();
                agentRechargeService.insert(entity);
                this.update(newAgent);
            });
        } catch (BizRuntimeException e) {
            log.error("代理商扣款异常:{},{}", id, money);
            throw e;
        } catch (Exception e) {
            log.error("代理商扣款失败:{},{}", id, money);
            throw new BizRuntimeException(UserResultCode.agentConsumException);
        }
        return true;
    }

    @Override
    public AgentUserModel getMainInfo(String id) {
        AgentUserModel user = this.getById(id);
        if (null == user) {
            throw new BizRuntimeException(UserResultCode.agentNotExist);
        }

        if (StrUtil.isNotBlank(user.getParentId())) {
            user = this.getById(user.getParentId());
        }

        BigDecimal discount = new BigDecimal("1");
        if (StrUtil.isNotBlank(user.getLevelId())) {
            AgentLevelModel level = agentLevelService.getById(user.getLevelId());
            if (null != level) {
                user.setLevelName(level.getName());
                discount = new BigDecimal(level.getDiscount());
            }
        }
        user.setDiscount(discount);
        return user;
    }

    @Override
    public String getMainId(String userId) {
        AgentUserModel agentUser = this.getById(userId);
        if (null == agentUser) {
            throw new BizRuntimeException(UserResultCode.agentNotExist);
        }
        if (StrUtil.isNotBlank(agentUser.getParentId())) {
            return agentUser.getParentId();
        }
        return agentUser.getId();
    }

    public static void main(String[] args) {
        String htmlStr = "<div><img src=\"http://47.95.209.196/easyteaching-core/mobile/teachingrecords/getUrl?path=teachrecord/2018-08-10/20180810161528fce8f644e8224841a291ea7633efb395.jpeg\" alt=\"\"></div><br>";

        String img = "";
        Pattern p_image;
        Matcher m_image;
        List<String> pics = new ArrayList<>();

        String regEx_img = "<img.*src\\s*=\\s*(.*?)[^>]*?>";
        p_image = Pattern.compile(regEx_img, Pattern.CASE_INSENSITIVE);
        m_image = p_image.matcher(htmlStr);
        while (m_image.find()) {
            img = img + "," + m_image.group();
            System.err.println(img);
            // Matcher m =
            // Pattern.compile("src=\"?(.*?)(\"|>|\\s+)").matcher(img); //匹配src
            Matcher m = Pattern.compile("src\\s*=\\s*\"?(.*?)(\"|>|\\s+)").matcher(img);

            while (m.find()) {
                pics.add(m.group(1));
            }
        }
        System.err.println(pics.get(0));


    }

    @Override
    public AgentUserModel builder() {
        return new AgentUserModel();
    }

//    @Override
//    public Map<String, Object> rpcSearch(Map<String, Object> param, long current, long size) {
//        Page<AgentUserModel> page = new Page<>();
//        page.setSize(size);
//        page.setCurrent(current);
//        List<AgentUserModel> agentUserModels = agentUserMapper.searchUser(page.offset(), page.getSize(), param, null, null);
//        var rpcAgentUserModels = agentUserModels.stream().map(m -> BeanUtil.copyProperties(m, RpcAgentUserModel.class)).collect(Collectors.toList());
//        long total = agentUserMapper.searchUserCount(param);
//        Map<String, Object> map = new HashMap<>();
//        map.put("current", page.getCurrent());
//        map.put("size", page.getSize());
//        map.put("total", total);
//        map.put("records", rpcAgentUserModels);
//        return map;
//    }

//    @Override
//    public RpcUserModel addAgentUser(RpcAgentUserModel rpcAgentUserModel) throws BizException {
//        String mobile = rpcAgentUserModel.getMobile();
//        String userId = userService.getUserIdByMobile(mobile);
//        AgentUserModel agentUserModel = BeanUtil.copyProperties(rpcAgentUserModel, AgentUserModel.class);
//        if (StrUtil.isBlank(userId)) {
//            agentUserModel.addUserType(UserType.agent);
//            IUserModel<?> userModel = loginServiceComposite.register(
//                    LoginInfoModel.builder()
//                            .account(rpcAgentUserModel.getUserName())
//                            .loginType(UserAccountType.username)
//                            .certificate(rpcAgentUserModel.getPassword())
//                            .build(),
//                    agentUserModel
//            );
//            return BeanUtil.copyProperties(userModel.toUserModel(), RpcUserModel.class);
//        } else {
//            UserModel userDetail = userService.getUserDetail(userId);
//            if (!Arrays.asList(userDetail.getHaveTypes()).contains(HaveType.ykt)) {
//                userDetail.addHaveType(HaveType.ykt);
//            }
//            if (!Arrays.asList(userDetail.getUserTypes()).contains(UserType.agent)) {
//                userDetail.addUserType(UserType.agent);
//            }
//            userService.update(userDetail.toUserModel());
//            AgentUserModel agentUser = agentUserMapper.selectById(userDetail.getId());
//            if (null == agentUser) {
//                agentUserModel.setId(userId);
//                agentUserMapper.insert(agentUserModel.clearUserModelMessage());
//            }
//            return BeanUtil.copyProperties(userDetail.toUserModel(), RpcUserModel.class);
//        }
//    }
//
//    @Override
//    public RpcAgentUserModel userDetail(String id) {
//        AgentUserModel userDetail = this.getUserDetail(id);
//        return BeanUtil.copyProperties(userDetail, RpcAgentUserModel.class);
//    }
//
//    @Override
//    public void rpcUpdate(RpcAgentUserModel agentUserModel) {
//        AgentUserModel userModel = BeanUtil.copyProperties(agentUserModel, AgentUserModel.class);
//        this.update(userModel);
//    }
//
//    @Override
//    public List<String> rpcSelectNextChildrenIds(String id) {
//        return this.selectNextChildrenIds(id);
//    }
//
//    @Override
//    public RpcAgentUserModel rpcUpdate(String id, Long money) {
//        AgentUserModel userModel = this.getById(id);
//        if (null == userModel) return null;
//        if (userModel.getBanance() < money) {
//            return null;
//        }
//        userModel.setId(userModel.getId());
//        userModel.setBanance(userModel.getBanance() - money);
//        userModel.setCumulativeConsumption(userModel.getCumulativeConsumption() + money);
//        AgentUserModel update = this.update(userModel);
//        if (null == update) return null;
//        return BeanUtil.copyProperties(update, RpcAgentUserModel.class);
//    }
    @Override
    public Boolean syncAgentUserToDistribute(){
        List<AgentUserModel> agentUserModels = agentUserMapper.selectAgentIds();

        QueryWrapper<DistributionUser> queryWrapper = new QueryWrapper<>();
//        queryWrapper.eq("deleted",false)
//                .isNull("levels_id")
//        ;
        queryWrapper
                .isNull("levels_id")
        ;
        List<DistributionUser> list = IDistributionUserService.list(queryWrapper);
//        筛选出没有的进行插入,agentUserModels里的id和list里的id进行对比，筛选出list没有的
//        新插入的
        List<DistributionUser> list1 = agentUserModels.stream().filter(agentUserModel -> {
            return list.stream().noneMatch(distributionUser -> {
               return distributionUser.getId().equals(agentUserModel.getId());

            });
        }).map((e)->{
            DistributionUser distributionUser = new DistributionUser();
            distributionUser.setId(e.getId());
            return distributionUser;
        }).toList();

//        禁用的再恢复的
//        List<DistributionUser> list2 = agentUserModels.stream().filter(agentUserModel -> {
//            return list.stream().anyMatch(distributionUser -> {
//               return distributionUser.getId().equals(agentUserModel.getId())&& distributionUser.getDeleted();
//            });
//        }).map((e)->{
//            DistributionUser distributionUser = new DistributionUser();
//            distributionUser.setId(e.getId());
//            return distributionUser;
//        }).toList();

        List<DistributionUser> list2 = list.stream().filter(distributionUser -> {
            return agentUserModels.stream().anyMatch(agentUserModel -> {
                return distributionUser.getId().equals(agentUserModel.getId())&& distributionUser.getDeleted();
            });
        }).peek((e)-> e.setDeleted(false)).toList();

//        批量默认1000条
        if(!list1.isEmpty()){
            IDistributionUserService.saveBatch(list1);
        }
        if(!list2.isEmpty()){
            IDistributionUserService.updateBatchById(list2);
        }
       return true;
    };
}
